
local skynet = require "skynet" 
require "skynet.manager"
local socket = require "socket"
local CMD = require "main_proto"
local CMDGAME = require "game_proto"
local Sraw = require "stable.raw"
local CalCard = require "calccard"
local Object = require("core").Object
local lobbysql = require "lobbysql"
local bufferrw = require "buffrw"

Sraw.init()

local buffwrite = bufferrw.BuffWrite
local buffread  = bufferrw.BuffRead

local randlist = nil
local GAME_ID = tonumber(skynet.getenv('game_id')) or 1001 
local PLATFORM_ID = tonumber(skynet.getenv('platform_type') or 1)
local ROOM_TYPE = tonumber(skynet.getenv('room_type') or 1)
local SER_STATUS = 1 --1：正常，0：停用

local playerList --= Sraw.create()   --table_uid:playerinfo
local roomList = {}
local roomIdleList = {}
local rand_use = 1
local center_conn   = skynet.localname(".center_con")

local function SendToCenter(mscmd, scmd, msg)
    if not center_conn then
        center_conn   = skynet.localname(".center_con")
    end
    skynet.send(center_conn,"lua","sendToCenter",mscmd, scmd, msg)
end

local function IsGold()
    return ROOM_TYPE == 2
end

local Manager = {}

function Manager.OnNetMsgCreateRoomReq(smsg, playerId)
    local Player = Sraw.get(playerList,tostring(playerId))
    local wJu, wZhiFuRen, nDiFen, nMa, nFangPaoOrZiMo,nDianPaoMaOrZiMoMa, 
    IsQG, wRoomType, nMaxPlayerCount,nGoupId, 
    externData = string.unpack("I2I2I4I4I4I4I4I2I4I4c128", smsg, 5)
    
    local nNeedCard = Manager.CalcCard(wZhiFuRen, wJu, nMaxPlayerCount)

    local result = Manager.PreCreateRoomDouHua(smsg,playerId,1)

    if result ~= 1 then
        local msg = string.pack(">I2>I2c96",CMD.Main_ClientAndGameSvr_UserModle, CMD.Sub_GameSvrToClient_UserModle_HingMsg,szResult)
        skynet.send(math.floor(Player.nAgentAddr),"lua", "send_data", msg)
        return
    end

    local roomId = Manager.GenerateTableId()
    print("roomId="..roomId)
    local room = skynet.newservice("Room")

    if room then
        roomList[roomId] = room
        skynet.call(room,"lua","Init",roomId,playerId,nMaxPlayerCount, wJu, nNeedCard, wZhiFuRen,
                    nDiFen, nMa, nFangPaoOrZiMo,  nDianPaoMaOrZiMoMa, nKeQiangGang, externData,nGoupId)
    end
    
    skynet.send(room,"lua","Join",Player)
end

function Manager.OnNetMsgEnterRoomReq(smsg, playerId)
    local Player = Sraw.get(playerList,tostring(playerId))
    local roomId, offbackflag = string.unpack("I4I1", smsg, 5)
    skynet.error("[manager]EnterRoom ", roomId, offbackflag)

    if IsGold() then --如果是金币场
        if Player.nRoomAddr > 0 then
            skynet.send(math.floor(Player.nRoomAddr),"lua","ReJoin",Player)
            return
        end
        if #roomIdleList <= 0 then
            local roomId = Manager.GenerateTableId()
            local room = skynet.newservice("GoldRoom")
            roomList[roomId] = room
            table.insert(roomIdleList,roomId)
            skynet.call(room,"lua","Init",roomId)
        end

        local room = roomList[roomIdleList[#roomIdleList]]
        skynet.send(room,"lua","Join",Player)
        return
    end

    if roomList[roomId] then
        if Player.nRoomAddr == roomList[roomId] then
            skynet.send(roomList[roomId],"lua","ReJoin",Player)
        else
            skynet.error("玩家坐下")
            skynet.send(roomList[roomId],"lua","Join",Player)
        end
    end

end

function Manager.GenerateTableId()
    local table_id_pre = skynet.getenv('table_id_pre') or 12 
    table_id_pre = table_id_pre * 10000

    if randlist == nil or rand_use >= 9000 then
        randlist = {}
        --[[
         按C++的算法，先把桌号都计算出来，再来随机
         这样计算出来的随机号能，按正常的速度取得出来
        --]]
        local havearry = {}
        for i=1, 9999 do
            havearry[i] = i
        end

        for i=1, 9999 do
            local rand = math.random(i, 9999)
            randlist[i] = havearry[rand]
            havearry[rand] = havearry[i]
        end
        rand_use = 1
    end

    while roomList[randlist[rand_use]] do
        rand_use = rand_use + 1
        skynet.error("GenerateTableId find rand_use use ", randlist[rand_use])
    end
    
    local tid = table_id_pre + randlist[rand_use]
    rand_use = rand_use + 1

    skynet.error('create an table, game id is ', GAME_ID, ' table_id is ', tid)
    return math.floor(tid)
end 

function Manager.GetPlayer(uid)
    return Sraw.get[tostring(uid)]
end

function Manager.OnNetMsgPreCreateAccountReq(smsg, playerId)-- 预创建房间
    local Player = Sraw.get(playerList,tostring(playerId))
    local result = 0
    if SER_STATUS == 1 then
       result  = Manager.PreCreateRoomDouHua(smsg,playerId,0)
    else
        local msg = string.pack(">I2>I2c96",CMD.Main_ClientAndGameSvr_UserModle, CMD.Sub_GameSvrToClient_UserModle_HingMsg,"服务器维护中")
        skynet.send(math.floor(Player.nAgentAddr),"lua", "send_data", msg)

        msg = string.pack(">I2>I2",CMD.Main_ClientAndGameSvr_UserModle,CMD.Sub_GameSvrToClient_UserModle_ServerDown)
        skynet.send(math.floor(Player.nAgentAddr),"lua", "send_data", msg)
        result = 0
    end


--[[
    if PLATFORM_ID == 2 then
        result = Manager.PreCreateRoomDouHua(smsg,playerId,0)
    else
       result = Manager.PreCreateRoom(smsg,Player) 
    end
]]
    local msg = string.pack(">I2>I2<I1",CMD.Main_ClientAndGameSvr_LobbyModle, CMD.Sub_GameSvrToClient_LobbyModle_PreCreateResult,result)
    skynet.send(math.floor(Player.nAgentAddr),"lua", "send_data", msg)
end

function Manager.CalcCard(wZhiFuRen, wJu, nMaxPlayerCount)
    local nNeedCard  = CalCard[GAME_ID](wZhiFuRen, wJu, nMaxPlayerCount)
    return nNeedCard
end

function Manager.PreCreateRoomDouHua(smsg,playerId,nCreateTrue)
    local player = Sraw.get(playerList,tostring(playerId))
    local result = 0
    local wJu, wZhiFuRen, nDiFen, nMa, nFangPaoOrZiMo,nDianPaoMaOrZiMoMa, 
    IsQG, wRoomType, nMaxPlayerCount,nGroupID, 
    externData = string.unpack("I2I2I4I4I4I4I4I2I4I4c128", smsg, 5)
    nNeedCard = Manager.CalcCard(wZhiFuRen, wJu, nMaxPlayerCount)
    if nGroupID > 0 then
        local ret,szResult = lobbysql.OnPreCreate(playerId,nMaxPlayerCount,nGroupID,nNeedCard,nCreateTrue)
        if ret == 1 then
            result = 1
        else
            local msg = string.pack(">I2>I2<c96",CMD.Main_ClientAndGameSvr_UserModle, CMD.Sub_GameSvrToClient_UserModle_HingMsg,szResult)
            skynet.send(math.floor(player.nAgentAddr),"lua", "send_data", msg)
        end
    else
        if player.nDiamond >= nNeedCard then
            result = 1
        else
            local msg = string.pack(">I2>I2c96",CMD.Main_ClientAndGameSvr_UserModle, CMD.Sub_GameSvrToClient_UserModle_HingMsg,"您的钻石余额不足，无法创建房间，请尽快充值!")
            skynet.send(math.floor(player.nAgentAddr),"lua", "send_data", msg)
        end
    end
    return result
end

function Manager.OnNetMsgPreEnterRoomReq(smsg, playerId) -- 预进入
    local Player = Sraw.get(playerList,tostring(playerId))
    if IsGold() then
        local is_enter = Player.llJinBi >= Manager.m_nMinEnterJinBi
        if not is_enter then
            local msg = string.pack(">I2>I2c96",CMD.Main_ClientAndGameSvr_UserModle, CMD.Sub_GameSvrToClient_UserModle_HingMsg,"您的金币不足")
            skynet.send(math.floor(Player.nAgentAddr),"lua", "send_data", msg)
        end

        if is_enter and Manager.m_nMaxEnterJinBi > 0 then
            is_enter = Player.llJinBi < Manager.m_nMaxEnterJinBi
            if not is_enter then
                local msg = string.pack(">I2>I2c96",CMD.Main_ClientAndGameSvr_UserModle, CMD.Sub_GameSvrToClient_UserModle_HingMsg,"您的金币超过上限")
                skynet.send(math.floor(Player.nAgentAddr),"lua", "send_data", msg)
            end
        end

        local msg = string.pack(">I2>I2<I1",CMD.Main_ClientAndGameSvr_LobbyModle, CMD.Sub_GameSvrToClient_LobbyModle_PreEnterResult,is_enter and 1 or 0)
        skynet.send(math.floor(Player.nAgentAddr),"lua", "send_data",msg)
        return
    end

    local table_id, offbackflag = string.unpack("I4I1", smsg, 5)
    skynet.error("[manager] OnNetMsgPreEnterRoomReq ", table_id, offbackflag)
    if roomList[table_id] then              --有房间信息直接发消息过去
        skynet.send(roomList[table_id],"lua","PreJoin",Player)
        return
    end 
    --没有房间进入失败
    local BuffWrite = buffwrite.new()
    BuffWrite:proto(CMD.Main_ClientAndGameSvr_UserModle, CMD.Sub_GameSvrToClient_UserModle_RoomID_Error) 
    skynet.error("[manager] OnNetMsgPreEnterRoomReq fail")
    --BuffWrite:int1(0)
    skynet.send(math.floor(Player.nAgentAddr), "lua", "send_data", BuffWrite.buff)
end

function Manager.DismissRoom(roomId)
    local nRoomId = math.floor(roomId)
    if roomList[nRoomId] then
        roomList[nRoomId] = nil
    end
    return true
end

local function send_package(fd, pack)
	local package  =  string.pack(">s2", pack)
	socket.write(fd,  package)
end

function Manager.PreCreateRoom(smsg,Player)
    local result = 0
    local BuffRead = buffread.new(smsg)
    BuffRead:proto()
    local wJu                   = BuffRead:int2()
    local wZhiFuRen             = BuffRead:int2()
    local nDiFen                = BuffRead:int4()
    local nMa                   = BuffRead:int4()
    local nFangPaoOrZiMo        = BuffRead:int4()
    local nDianPaoMaOrZiMoMa    = BuffRead:int4()
    local nKeQiangGang          = BuffRead:int4()
    local wRoomType             = BuffRead:int2()
    local nMaxPlayerCount       = BuffRead:int4()
    local externData            = BuffRead:str(128)
    local nNeedCard = Manager.CalcCard(wZhiFuRen, wJu, nMaxPlayerCount)
    result = Player.nDiamond >= nNeedCard and 1 or 0
    if 0 == result then
        local msg = string.pack(">I2>I2c96",CMD.Main_ClientAndGameSvr_UserModle, CMD.Sub_GameSvrToClient_UserModle_HingMsg,"您的钻石余额不足，无法创建房间，请尽快充值。")
        skynet.send(math.floor(Player.nAgentAddr),"lua", "send_data", msg)
    end

    return result
end

function Manager.OnTimer1MinGetSystemMsg()-- 1分钟定时器
    skynet.sleep(6000)
    skynet.call(skynet.localname(".sql"), "lua", "OnGetSystemMsg")
end

function Manager.OnUserGateInfor(smsg)
    local client_addr = string.unpack("z", smsg,  5)    
    skynet.error("[manager] client_addr: ", client_addr)
    --player.szIp = client_addr
    --player.nStat = 1
    return client_addr
end

function Manager.OnNetMsgPlayerZhanjiReq(Player)  -- 读战绩
    skynet.error("[manager] OnNetMsgPlayerZhanjiReq ")
    local result=skynet.call(skynet.localname(".sql"), "lua", "OnNetMsgPlayerZhanjiReq",Player.nPlayerId)
    
    local BuffWrite = buffwrite.new()
    BuffWrite:proto(300, 2009)
    if result.bSucc then         
        BuffWrite:int4(result.nCount)        
        for k , OneZhanJi in pairs(result.OneZhanJiList) do 
        
            BuffWrite:int4(OneZhanJi.nIdx)
            BuffWrite:int4(OneZhanJi.nTableId)
            BuffWrite:int4(OneZhanJi.nRound)           
            BuffWrite:int4(OneZhanJi.nGameId)
            BuffWrite:int2(OneZhanJi.wMyChairId)
            
            for i = 1, 8 do
                BuffWrite:int4(OneZhanJi.nScores[i])
            end
            for i = 1, 8 do
                BuffWrite:str(OneZhanJi.szNames[i],64)
            end            
            BuffWrite:str(OneZhanJi.szTime,32)           
        end        
    end
    skynet.send(Player.nAgentAddr,"lua","send_data",BuffWrite.buff)         
end

function Manager.start(playerlist)
    playerList = playerlist
    skynet.fork(Manager.OnTimer1MinGetSystemMsg) 
end

--代理开房
function Manager.OnNetMsgCreateAgentRoomReq(smsg)
    local nGameID,nAgentID,nMode,wJu,nDiFen,nMa,
    nFangPaoOrZiMo,nDianPaoMaOrZiMoMa,nKeQiangGang,nMaxPlayerCount,
    externData = string.unpack("I4I4I4I2I4I4I4I4I4I4c128",smsg)
    skynet.error("Manager:nMaxPlayerCount = ", nMaxPlayerCount)
    --支付人默认为房主支付
    local wZhiFuRen = 1
    local nNeedCard = Manager.CalcCard(wZhiFuRen, wJu, nMaxPlayerCount)

    local roomId = Manager.GenerateTableId()
    local room = nil
    if roomId then
        room = skynet.newservice("Room")
    end

    if not room then
        local msg = string.pack("I4I4c128",math.floor(nAgentID),0,"创建房间失败！")
            SendToCenter(CMD.Main_Hall_CMD,CMD.Sub_CreateAgentTableResp2,msg)
        return
    end

    roomList[roomId] = room
    skynet.call(room,"lua","Init",roomId,math.floor(nAgentID),nMaxPlayerCount, wJu, nNeedCard, wZhiFuRen,
                nDiFen, nMa, nFangPaoOrZiMo,  nDianPaoMaOrZiMoMa, nKeQiangGang, externData,nAgentID)
    skynet.send(room,"lua","InitAgentInfo",nMode)
end
--代理解散房间
function Manager.OnNetMsgDismissAgentRoomReq(smsg)
    local nAgentID,nRoomId = string.unpack("I4I4",smsg)

    local pResp = lobbysql.OnAgentDismissTable(nRoomId,nAgentID)
    local msg = string.pack("I4I4I4",pResp.nPlayerID,pResp.nTableID,pResp.nResult)
    SendToCenter(CMD.Main_Hall_CMD,CMD.Sub_AgentDismissTableResp,msg)

    local room = roomList[nRoomId]
    if not room then
        return
    end
    skynet.send(room,"lua","AgentDismissRoom",nAgentID)
end

function Manager.OnRecvHallMsg(mcmd, scmd, msg,sz)
    skynet.error(" OnRecvHallMsg mcmd: ", mcmd, " scmd: ", scmd)
    if mcmd == CMD.Main_Hall_CMD then
        if scmd == CMD.Sub_CreateAgentTableReq2 then --代理代开房
            Manager.OnNetMsgCreateAgentRoomReq(msg)
        elseif scmd == CMD.Sub_AgentDismissTableReq then --代理解散房间
            Manager.OnNetMsgDismissAgentRoomReq(msg)
        end
    end
end

function Manager.TableNotIdle(nRoomId)
    for i,k in ipairs(roomIdleList) do
        if k == nRoomId then
            table.remove(roomIdleList,i)
            return
        end
    end
    
end

function Manager.TableIdle(nRoomId)
    table.insert(roomIdleList,math.floor(nRoomId))
end

function Manager.LoadGlobalCfg()
    while true do
        skynet.sleep(100*60)
        local file = io.open("GlobalCfg.lua","r")
        if file then
            local value = file:read("*a")
            local globalCfg = load(value)()
            if globalCfg then
                SER_STATUS = globalCfg.SER_STATUS
            end
            skynet.error("SER_STATUS = ",SER_STATUS)
            file:close()
        end
        if SER_STATUS ~= 1 then
            for _,room in pairs(roomList) do
                skynet.send(room,"lua","GameServerUpdate",nMode)
            end
            --break
        end
    end 
end

skynet.start(function()
    skynet.error("manager server start...")
    skynet.dispatch("lua", function(_ , _ ,  command ,  ...)
        local f  =  Manager[command]
        skynet.ret(skynet.pack(f(...)))
    end)
    skynet.register ".manager"
    math.randomseed(os.time())

    if IsGold() then
        Manager.m_nMinEnterJinBi = tonumber(skynet.getenv('nMinEnterJinBi') or 1)
        Manager.m_nMaxEnterJinBi = tonumber(skynet.getenv('nMaxEnterJinBi') or 0)
    end

    skynet.fork(Manager.LoadGlobalCfg)
end)
